@isTest
private class Milestone1_Test_Import_Export {

	static testMethod void testProjectManyMilestonesManyTasksImportExport() {
	    final Integer NUMBER_OF_MILESTONES = 100;
	    final Integer NUMBER_OF_TASKS = 100;
	    Document doc;
	    String projectXML;
	    
	    //create a project
	    Milestone1_Project__c project = Milestone1_Test_Utility.sampleProjectActive('proj');
	    insert project;
	    
	    //create a many milestones underneath project
	    List<Milestone1_Milestone__c> milestones = manyMilestones(project, null,NUMBER_OF_MILESTONES);
	    
	    //create tasks linked to milestones
	    List<Milestone1_Task__c> tasks = new List<Milestone1_Task__c>();
	    for(Integer i = 0; i < NUMBER_OF_TASKS; i++){
	        Id parentMilestoneId = milestones[(Math.random() * milestones.size()).intValue()].Id;
	        Milestone1_Task__c taskRec = Milestone1_Test_Utility.sampleTask(parentMilestoneId);
	        tasks.add(taskRec);
	    }
	    insert tasks;
	    
	    //create export page controller and call export action
	    ApexPages.StandardController stc = new ApexPages.StandardController(project);
	    Milestone1_Export_Project_Controller exportProjectController = new Milestone1_Export_Project_Controller(stc);
	    exportProjectController.createExportXML();
	    doc = exportProjectController.doc;
	    projectXML = String.valueOf(doc.Body.toString());  
	    
	    checkProject(project,projectXML);
	    checkMilestones(milestones,projectXML);
	    checkTasks(tasks,projectXML);
	    
	    //make some changes to it 
	    modifyProject(project);
	    modifyMilestones(milestones);
	    modifyTasks(tasks);
	    
	    //call export action with the new 
	    exportProjectController.createExportXML();
	    doc = exportProjectController.doc;
	    projectXML = String.valueOf(doc.Body.toString());  
	    
	    // validate
	    checkProject(project,projectXML);
	    checkMilestones(milestones,projectXML);
	    checkTasks(tasks,projectXML);
	    
	    //make some changes to it 
	    modifyProject(project);
	    modifyMilestones(milestones);
	    modifyTasks(tasks);
	    
	    //delete project
	    stc.delete();
	    
	    //create import page controller and call import action
	    Milestone1_Import_Project_Controller importProjectController = new Milestone1_Import_Project_Controller(null);
	    importProjectController.docId = doc.Id;
	    projectXML = importProjectController.getDocumentXMLString();
	    
	    // validate 
	    checkProject(project,projectXML);
	    checkMilestones(milestones,projectXML);
	    checkTasks(tasks,projectXML);
	    
    }
    
	/**
    * 	Create a batch of milestones
    */
    private static List<Milestone1_Milestone__c> manyMilestones(Milestone1_Project__c project,
    															Milestone1_Milestone__c parentMilestone, Integer size){
    	Milestone1_Milestone__c milestone;
    	List<Milestone1_Milestone__c> milestones = new List<Milestone1_Milestone__c>();
    	Id projectId,parentMilestoneId;
    	if(project != null){
    		projectId = project.Id;	
    	}
    	if(parentMilestone !=  null){
    		parentMilestoneId = milestone.Id;
    	}
    	for(Integer i = 0; i < size; i++){
        	milestone = Milestone1_Test_Utility.sampleMilestone(projectId, parentMilestoneId, 'ms'+i);
        	milestones.add(milestone);
        }
        insert milestones;
        return milestones;	
    }
    
    private static void checkProject(Milestone1_Project__c project,String xml){
    	System.assert(checkField(project,'Id',xml), assertMessage('Id',String.valueOf(project.Id)));
    	System.assert(checkField(project,'Total_Hours_Budget__c',xml), assertMessage('Total_Hours_Budget__c',String.valueOf(project.Total_Hours_Budget__c)));
    	System.assert(checkField(project,'Total_Expense_Budget__c',xml), assertMessage('Total_Expense_Budget__c',String.valueOf(project.Total_Expense_Budget__c)));
    	System.assert(checkField(project,'Status__c',xml), assertMessage('Status__c',String.valueOf(project.Status__c)));
    	System.assert(checkField(project,'Description__c',xml), assertMessage('Description__c',String.valueOf(project.Description__c)));
    	System.assert(checkField(project,'Name',xml),assertMessage('Name',String.valueOf(project.Name)));    	
    }
    
    private static void checkMilestones(List<Milestone1_Milestone__c> milestones,String xml){
    	for(Milestone1_Milestone__c milestone : milestones){
    		System.assert(checkField(milestone,'Id',xml), assertMessage('Id',String.valueOf(milestone.Id))); 
    		System.assert(checkField(milestone,'Description__c',xml), assertMessage('Description__c',String.valueOf(milestone.Description__c))); 
    		System.assert(checkField(milestone,'Expense_Budget__c',xml), assertMessage('Expense_Budget__c',String.valueOf(milestone.Expense_Budget__c))); 
    		System.assert(checkField(milestone,'Hours_Budget__c',xml), assertMessage('Hours_Budget__c',String.valueOf(milestone.Hours_Budget__c))); 
    		System.assert(checkField(milestone,'Name',xml), assertMessage('Name',String.valueOf(milestone.Name))); 
    		System.assert(checkField(milestone,'Alias__c',xml), assertMessage('Alias__c',String.valueOf(milestone.Alias__c))); 	
    	}   	
    }
    
    private static void checkTasks(List<Milestone1_Task__c> tasks,String xml){
    	for(Milestone1_Task__c task : tasks){
    		System.assert(checkField(task,'Id',xml), assertMessage('Id',String.valueOf(task.Id))); 
    		System.assert(checkField(task,'Description__c',xml), assertMessage('Description__c',String.valueOf(task.Description__c))); 
    		System.assert(checkField(task,'Estimated_Hours__c',xml), assertMessage('Estimated_Hours__c',String.valueOf(task.Estimated_Hours__c))); 
    		System.assert(checkField(task,'Estimated_Expense__c',xml), assertMessage('Estimated_Expense__c',String.valueOf(task.Estimated_Expense__c))); 
    		System.assert(checkField(task,'Name',xml), assertMessage('Name',String.valueOf(task.Name)));  	
    	}   	
    }
    
    private static void modifyProject(Milestone1_Project__c project){
     	Date today = Date.today();
     	project.Description__c = String.valueOf(today);
     	project.Name = String.valueOf(today);
     	update project;
    }
	
	private static void modifyMilestones(List<Milestone1_Milestone__c> milestones){
		Date today = Date.today();
     	for(Milestone1_Milestone__c milestone : milestones){
     		milestone.Description__c = String.valueOf(today);
     		milestone.Name = String.valueOf(today);	
     	}
     	update milestones;
	}
	
	private static void modifyTasks(List<Milestone1_Task__c> tasks){
		Date today = Date.today();
     	for(Milestone1_Task__c task : tasks){
     		task.Description__c = String.valueOf(today);
     		task.Name = String.valueOf(today);	
     	}
     	update tasks;
	}
    
    private static Boolean checkField(Sobject myObject,String field,String xml){
    	String fieldValue = String.valueOf(myObject.get(field));
    	return fieldValue == null || xml.indexOf(EncodingUtil.urlEncode(fieldValue,'UTF-8')) > 0;
    }
    
    private static String assertMessage(String param1,String param2){
    	if(param2 == null){
    		param2 = '';
    	}
    	return 'error in '+param1+' fieldName with value '+param2;
    }
}